package cn.anecansaitin.whimsy.common.extension.comboSystem;

import net.minecraft.world.entity.player.Player;


/*
 * 怕自己忘记，记录一下这里的思路。
 * 为了把按键输入与执行的代码区分开，分成了tick和inputKey。
 *
 * 每个tick都执行一次技能，当技能返回true时表示技能完全执行完了，
 * 没有派生任何技能。
 * 如果返回false，表示还在执行中，那么就先询问当前是否能派生技能。
 * 如果可以派生则返回NEXT状态与缓存的key，如果没有缓存key则返回
 * EXECUTING。既没有返回true，又不可派生则表示还在执行阶段，也
 * 返回EXECUTING。
 *
 * inputKey处理每一次的按键输入，接收到按键后询问当前是否可以缓存
 * 按键，如若可以则缓存。缓存后的按键会在tick方法中用到。
 *
 * 之所以要分成是否可以派生与是否可以缓存key，是为了派生的连贯性，
 * 玩家可以在技能可派生前就输入按键，这样就能确保派生的技能可以在
 * 第一时间触发。但如果从技能开始到结束一直可以缓存key，那么会导致
 * 玩家在触发上一个派生时多按了几次按键，导致key进行了缓存，派生就
 * 没法取消了。
 * */
public class SkillPerformer {
    private ISkill skill = ISkill.EMPTY;
    private final ExtraData extra = new ExtraData();
    private int skillTick = 0;
    private int keyCache = 0;
    /**
     * 派生出该技能的按键
     */
    private int key = 0;

    public ExecuteState tick(Player player) {
        boolean execute = skill.execute(skillTick++, player, extra);

        if (skill instanceof IChargeableSkill) {
            ((IChargeableSkill) skill).setCharging(extra, false);
        }

        if (execute) {
            return ExecuteState.finished();
        } else if (skill.canDeriving(skillTick, extra)) {
            return keyCache == 0 ? ExecuteState.executing() : ExecuteState.next(keyCache);
        } else {
            return ExecuteState.executing();
        }
    }

    public void inputKey(int key) {
        if (skill.canCachingKey(skillTick, extra)) {
            keyCache = key;

            if (skill instanceof IChargeableSkill) {
                ((IChargeableSkill) skill).setCharging(extra, key == this.key);
            }
        }
    }

    public void setSkill(ISkill skill, int key) {
        this.skill = skill;
        skillTick = 0;
        keyCache = 0;
        this.key = key;
    }

    public void putExtraData(String name, Object data) {
        extra.putData(name, data);
    }

    public ISkill getSkill() {
        return skill;
    }

    public record ExecuteState(State state, int key) {
        public static ExecuteState executing() {
            return new ExecuteState(State.EXECUTING, 0);
        }

        public static ExecuteState next(int key) {
            return new ExecuteState(State.NEXT, key);
        }

        public static ExecuteState finished() {
            return new ExecuteState(State.FINISHED, 0);
        }

        public enum State {
            /**
             * 正在执行
             */
            EXECUTING,
            /**
             * 可以派生技能
             */
            NEXT,
            /**
             * 执行完毕，不可派生技能
             */
            FINISHED
        }
    }
}
